// GPSCompass.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

#include "GPSCompass.h"
#include "GPS.h"

// [CF] - TODO - is this already defined somewhere else for me???
#define M_PI 3.14159265358979323846 /* pi */

static BOOL g_bShowStatus = FALSE;

INT_PTR CALLBACK GPSCompassDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	HWND hWndCtrl;

    switch (message)
    {
        case WM_INITDIALOG:
            {
                // Create a Done button and size it.  
                SHINITDLGINFO shidi;
				SHMENUBARINFO mbi;

                shidi.dwMask = SHIDIM_FLAGS;
                shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
                shidi.hDlg = hDlg;
                SHInitDialog(&shidi);

				// Create a menu bar
                memset(&mbi, 0, sizeof(SHMENUBARINFO));
				mbi.cbSize     = sizeof(SHMENUBARINFO);
				mbi.hwndParent = hDlg;
				mbi.nToolBarId = IDR_MENU;
				mbi.hInstRes   = GetModuleHandle(NULL);
				mbi.dwFlags = SHCMBF_HMENU;
	            SHCreateMenuBar(&mbi);

				// Start a timer to update the compass rose
				SetTimer(hDlg, 1, 500, NULL);
            }
            return (INT_PTR)TRUE;

		case WM_INITMENUPOPUP:
			// The menu is about to popup so enable/disable
			// the various menu items depending upon the state
			// of the application.
			if (GPS_IsOpened())
			{
				EnableMenuItem((HMENU)wParam, IDM_GPS_START, MF_BYCOMMAND | MF_GRAYED);
				EnableMenuItem((HMENU)wParam, IDM_GPS_STOP,  MF_BYCOMMAND | MF_ENABLED);
			}
			else
			{
				EnableMenuItem((HMENU)wParam, IDM_GPS_START, MF_BYCOMMAND | MF_ENABLED);
				EnableMenuItem((HMENU)wParam, IDM_GPS_STOP,  MF_BYCOMMAND | MF_GRAYED);
			}

			if (g_bShowStatus)
			{
				CheckMenuItem((HMENU)wParam, IDM_GPS_STATUS, MF_BYCOMMAND | MF_CHECKED);
			}
			else
			{
				CheckMenuItem((HMENU)wParam, IDM_GPS_STATUS, MF_BYCOMMAND | MF_UNCHECKED);
			}
			break;

        case WM_COMMAND:
            switch (LOWORD(wParam))
			{
				case IDOK:
		            EndDialog(hDlg, LOWORD(wParam));
					return (INT_PTR)TRUE;

				case IDM_GPS_START:
					if (!GPS_IsOpened())
					{
						GPS_Open();
					}
					break;
           
				case IDM_GPS_STOP:
					if (GPS_IsOpened())
					{
						GPS_Close();
					}
					break;

				case IDM_GPS_STATUS:
					// Toggle between the status and compass displays
					g_bShowStatus = !g_bShowStatus;
					
					hWndCtrl = GetDlgItem(hDlg, IDC_COMPASS_ROSE);
					ShowWindow(hWndCtrl, !g_bShowStatus ? SW_SHOW : SW_HIDE);

					hWndCtrl = GetDlgItem(hDlg, IDC_COMPASS_POINT);
					ShowWindow(hWndCtrl, !g_bShowStatus ? SW_SHOW : SW_HIDE);

					hWndCtrl = GetDlgItem(hDlg, IDC_HEADING_LABEL);
					ShowWindow(hWndCtrl, !g_bShowStatus ? SW_SHOW : SW_HIDE);

					hWndCtrl = GetDlgItem(hDlg, IDC_HEADING);
					ShowWindow(hWndCtrl, !g_bShowStatus ? SW_SHOW : SW_HIDE);

					hWndCtrl = GetDlgItem(hDlg, IDC_STATUS);
					ShowWindow(hWndCtrl, g_bShowStatus ? SW_SHOW : SW_HIDE);
					break;
			}
            break;

		case WM_TIMER:
			if (!g_bShowStatus)
			{
				// If showing the compass then toggle the
				// compass point visibility
				hWndCtrl = GetDlgItem(hDlg, IDC_COMPASS_POINT);
				if (IsWindowVisible(hWndCtrl))
					ShowWindow(hWndCtrl, SW_HIDE);
				else
					ShowWindow(hWndCtrl, SW_SHOW);
			}

			// Check if the GPS has updated state or position
			// information available
			if (GPS_DataHasChanged())
			{
				GPS_POSITION pos;
				GPS_DEVICE device;
				WCHAR szBuffer[2048], szBuffer2[128];

				// Get the current GPS location information
				GPS_GetData(&pos, &device);

				// Format the GPS location information into
				// a status message
				swprintf(szBuffer, L"%s %s %s\n",
					device.szGPSFriendlyName,
					GPS_GetServiceStateDescription(device.dwServiceState),
					GPS_GetServiceStateDescription(device.dwDeviceState));

				if (pos.dwValidFields & GPS_VALID_LATITUDE)
				{
					swprintf(szBuffer2, L"Latitude (DD):\n   %f\n", pos.dblLatitude);
					wcscat(szBuffer, szBuffer2);

					wcscat(szBuffer, L"Latitude (D,M,S):\n   ");
					GPS_FormatDegreesMinutesSeconds(szBuffer2, pos.dblLatitude);
					wcscat(szBuffer, szBuffer2);
					wcscat(szBuffer, L"\n");
				}
	
				if (pos.dwValidFields & GPS_VALID_LONGITUDE)
				{
					swprintf(szBuffer2, L"Longitude (DD):\n   %f\n", pos.dblLongitude);
					wcscat(szBuffer, szBuffer2);

					wcscat(szBuffer, L"Longitude (D,M,S):\n   ");
					GPS_FormatDegreesMinutesSeconds(szBuffer2, pos.dblLongitude);
					wcscat(szBuffer, szBuffer2);
					wcscat(szBuffer, L"\n");
				}

				if ((pos.dwValidFields & GPS_VALID_SATELLITES_USED_PRNS) &&
                       (pos.dwValidFields & GPS_VALID_SATELLITES_IN_VIEW) &&
					(pos.dwValidFields & GPS_VALID_SATELLITE_COUNT))
				{
					int iSatellitesInSolution = 0;
					for (int i = 0; i < pos.dwSatelliteCount; i++)
					{
						for (int j = 0; j < pos.dwSatellitesInView; j++)
						{
							if (pos.rgdwSatellitesUsedPRNs[i] == pos.rgdwSatellitesInViewPRNs[j])
							{
								iSatellitesInSolution++;
								break;
							}
						}
					}

					swprintf(szBuffer2, L"Satellite Count:\n   %d/%d (%d)\n",
						iSatellitesInSolution,
						pos.dwSatellitesInView,
						pos.dwSatelliteCount);
					wcscat(szBuffer, szBuffer2);
				}

				if (pos.dwValidFields & GPS_VALID_UTC_TIME)
				{
					wcscat(szBuffer, L"Time:\n   ");

					GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &pos.stUTCTime, NULL, szBuffer2, sizeof(szBuffer2) / sizeof(szBuffer2[0])); 
					wcscat(szBuffer, szBuffer2);

					wcscat(szBuffer, L" ");

					GetTimeFormat(LOCALE_USER_DEFAULT, 0, &pos.stUTCTime, NULL, szBuffer2, sizeof(szBuffer2) / sizeof(szBuffer2[0])); 
					wcscat(szBuffer, szBuffer2);

					wcscat(szBuffer, L"\n");
				}

				// Update the status label
				hWndCtrl = GetDlgItem(hDlg, IDC_STATUS);
				SetWindowText(hWndCtrl, szBuffer);

				// Update the heading label
				swprintf(szBuffer, L"%0.2f", pos.flHeading);
				hWndCtrl = GetDlgItem(hDlg, IDC_HEADING);
				SetWindowText(hWndCtrl, szBuffer);

				// Move the compass point
                int left = (int)(116 + 100 * sin(pos.flHeading * M_PI / 180));
				int top = (int)(116 - 100 * cos(pos.flHeading * M_PI / 180));
				hWndCtrl = GetDlgItem(hDlg, IDC_COMPASS_POINT);
				SetWindowPos(hWndCtrl, NULL, left, top, 0, 0, SWP_NOSIZE);
			}
			break;

        case WM_CLOSE:
			KillTimer(hDlg, 1);

			if (GPS_IsOpened())
			{
				GPS_Close();
			}

			EndDialog(hDlg, message);
            return (INT_PTR)TRUE;

    }
    return (INT_PTR)FALSE;
}

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
	return DialogBox(hInstance, (LPCTSTR)IDD_GPSCOMPASS, NULL, GPSCompassDialog);
}